home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / futilsrc.zoo / fileutil / src / chmod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-27  |  6.5 KB  |  279 lines

  1. /* chmod -- change permission modes of files
  2.    Copyright (C) 1989-1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Options:
  19.    -L    Dereference symbolic links (recursively change the modes of
  20.     directories pointed to by symbolic links).
  21.    -R    Recursively change modes of directory contents.
  22.    -c    Verbosely describe only files whose modes actually change.
  23.    -f    Do not print error messages about files.
  24.    -v    Verbosely describe changed modes.
  25.  
  26.    David MacKenzie <djm@ai.mit.edu> */
  27.  
  28. #include <stdio.h>
  29. #include <getopt.h>
  30. #include <sys/types.h>
  31. #include "modechange.h"
  32. #include "system.h"
  33.  
  34. int lstat ();
  35. int stat ();
  36.  
  37. char *savedir ();
  38. char *xmalloc ();
  39. char *xrealloc ();
  40. int change_file_mode ();
  41. int change_dir_mode ();
  42. void describe_change ();
  43. void error ();
  44. void mode_string ();
  45. void usage ();
  46.  
  47. /* The name the program was run with. */
  48. char *program_name;
  49.  
  50. /* If nonzero, change the modes of directories recursively. */
  51. int recurse;
  52.  
  53. /* If nonzero, force silence (no error messages). */
  54. int force_silent;
  55.  
  56. /* If nonzero, describe the modes we set. */
  57. int verbose;
  58.  
  59. /* If nonzero, describe only modes that change. */
  60. int changes_only;
  61.  
  62. /* A pointer to either lstat or stat. */
  63. int (*xstat) ();
  64.  
  65. /* Parse the ASCII mode given on the command line into a linked list
  66.    of `struct mode_change' and apply that to each file argument. */
  67.  
  68. void
  69. main (argc, argv)
  70.      int argc;
  71.      char **argv;
  72. {
  73.   struct mode_change *changes;
  74.   int errors = 0;
  75.   int modeind = 0;        /* Index of the mode argument in `argv'. */
  76.   int thisind;
  77.   int c;
  78.  
  79.   program_name = argv[0];
  80.   recurse = force_silent = verbose = changes_only = 0;
  81.   xstat = lstat;
  82.  
  83.   while (1)
  84.     {
  85.       thisind = optind ? optind : 1;
  86.  
  87.       c = getopt (argc, argv, "LRcfvrwxXstugoa,+-=");
  88.       if (c == EOF)
  89.     break;
  90.  
  91.       switch (c)
  92.     {
  93.     case 'r':
  94.     case 'w':
  95.     case 'x':
  96.     case 'X':
  97.     case 's':
  98.     case 't':
  99.     case 'u':
  100.     case 'g':
  101.     case 'o':
  102.     case 'a':
  103.     case ',':
  104.     case '+':
  105.     case '-':
  106.     case '=':
  107.       if (modeind != 0 && modeind != thisind)
  108.         error (1, 0, "invalid mode");
  109.       modeind = thisind;
  110.       break;
  111.     case 'L':
  112.       xstat = stat;
  113.       break;
  114.     case 'R':
  115.       recurse = 1;
  116.       break;
  117.     case 'c':
  118.       verbose = 1;
  119.       changes_only = 1;
  120.       break;
  121.     case 'f':
  122.       force_silent = 1;
  123.       break;
  124.     case 'v':
  125.       verbose = 1;
  126.       break;
  127.     default:
  128.       usage ();
  129.     }
  130.     }
  131.  
  132.   if (modeind == 0)
  133.     modeind = optind++;
  134.   if (optind >= argc)
  135.     usage ();
  136.  
  137.   changes = mode_compile (argv[modeind],
  138.               MODE_MASK_EQUALS | MODE_MASK_PLUS | MODE_MASK_MINUS);
  139.   if (changes == MODE_INVALID)
  140.     error (1, 0, "invalid mode");
  141.   else if (changes == MODE_MEMORY_EXHAUSTED)
  142.     error (1, 0, "virtual memory exhausted");
  143.  
  144.   for (; optind < argc; ++optind)
  145.     errors |= change_file_mode (argv[optind], changes);
  146.  
  147.   exit (errors);
  148. }
  149.  
  150. /* Change the mode of FILE according to the list of operations CHANGES.
  151.    Return 0 if successful, 1 if errors occurred. */
  152.  
  153. int
  154. change_file_mode (file, changes)
  155.      char *file;
  156.      struct mode_change *changes;
  157. {
  158.   struct stat file_stats;
  159.   unsigned short newmode;
  160.   int errors = 0;
  161.  
  162.   if ((*xstat) (file, &file_stats))
  163.     {
  164.       if (force_silent == 0)
  165.     error (0, errno, "%s", file);
  166.       return 1;
  167.     }
  168. #ifdef S_ISLNK
  169.   if (S_ISLNK (file_stats.st_mode))
  170.     return 0;
  171. #endif
  172.  
  173.   newmode = mode_adjust (file_stats.st_mode, changes);
  174.  
  175.   if (newmode != (file_stats.st_mode & 07777))
  176.     {
  177.       if (verbose)
  178.     describe_change (file, newmode, 1);
  179.       if (chmod (file, (int) newmode))
  180.     {
  181.       if (force_silent == 0)
  182.         error (0, errno, "%s", file);
  183.       errors = 1;
  184.     }
  185.     }
  186.   else if (verbose && changes_only == 0)
  187.     describe_change (file, newmode, 0);
  188.  
  189.   if (recurse && S_ISDIR (file_stats.st_mode))
  190.     errors |= change_dir_mode (file, changes, &file_stats);
  191.   return errors;
  192. }
  193.  
  194. /* Recursively change the modes of the files in directory DIR
  195.    according to the list of operations CHANGES.
  196.    STATP points to the results of lstat or stat on DIR.
  197.    Return 0 if successful, 1 if errors occurred. */
  198.  
  199. int
  200. change_dir_mode (dir, changes, statp)
  201.      char *dir;
  202.      struct mode_change *changes;
  203.      struct stat *statp;
  204. {
  205.   char *name_space, *namep;
  206.   char *path;            /* Full path of each entry to process. */
  207.   unsigned dirlength;        /* Length of DIR and '\0'. */
  208.   unsigned filelength;        /* Length of each pathname to process. */
  209.   unsigned pathlength;        /* Bytes allocated for `path'. */
  210.   int errors = 0;
  211.  
  212.   errno = 0;
  213.   name_space = savedir (dir, statp->st_size);
  214.   if (name_space == NULL)
  215.     {
  216.       if (errno)
  217.     {
  218.       if (force_silent == 0)
  219.         error (0, errno, "%s", dir);
  220.       return 1;
  221.     }
  222.       else
  223.     error (1, 0, "virtual memory exhausted");
  224.     }
  225.  
  226.   dirlength = strlen (dir) + 1;    /* + 1 is for the trailing '/'. */
  227.   pathlength = dirlength + 1;
  228.   /* Give `path' a dummy value; it will be reallocated before first use. */
  229.   path = xmalloc (pathlength);
  230.   strcpy (path, dir);
  231.   path[dirlength - 1] = '/';
  232.  
  233.   for (namep = name_space; *namep; namep += filelength - dirlength)
  234.     {
  235.       filelength = dirlength + strlen (namep) + 1;
  236.       if (filelength > pathlength)
  237.     {
  238.       pathlength = filelength * 2;
  239.       path = xrealloc (path, pathlength);
  240.     }
  241.       strcpy (path + dirlength, namep);
  242.       errors |= change_file_mode (path, changes);
  243.     }
  244.   free (path);
  245.   free (name_space);
  246.   return errors;
  247. }
  248.  
  249. /* Tell the user the mode MODE that file FILE has been set to;
  250.    if CHANGED is zero, FILE had that mode already. */
  251.  
  252. void
  253. describe_change (file, mode, changed)
  254.      char *file;
  255.      unsigned short mode;
  256.      int changed;
  257. {
  258.   char perms[11];        /* "-rwxrwxrwx" ls-style modes. */
  259.  
  260.   mode_string (mode, perms);
  261.   perms[10] = '\0';        /* `mode_string' does not null terminate. */
  262.   if (changed)
  263.     printf ("mode of %s changed to %04o (%s)\n",
  264.         file, mode & 07777, &perms[1]);
  265.   else
  266.     printf ("mode of %s retained as %04o (%s)\n",
  267.         file, mode & 07777, &perms[1]);
  268. }
  269.  
  270. void
  271. usage ()
  272. {
  273.   fprintf (stderr, "\
  274. Usage: %s [-LRcfv] mode file...\n\
  275.        mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number\n",
  276.        program_name);
  277.   exit (1);
  278. }
  279.